#include "GridDataAlgorithm.h"
#include "VolumeOptions.h"
#include "immintrin.h"
#include "fp16/fp16.h"
#include "VolumeEncoder.h"

namespace OCPP
{
	using namespace Volume;
	String GridDataAlgorithm::mergeVarName(GridDataVec& gridDataVec, const VolumeOptions& options)
	{
		String varName;
		bool sameSize = true;
		StringVector sv;
		for (const auto& gridData : gridDataVec)
		{
			sv.push_back(gridData.varName);
			if (varName.empty()) varName = gridData.varName;
			if (varName.size() != gridData.varName.size())
			{
				sameSize = false;
				break;
			}
		}

		StringStream sstream;

		if (sameSize)
		{
			const auto numName = sv.size();
			const auto size = varName.size();

			for (auto i = 0; i < size; i++)
			{
				auto c0 = varName[i];
				sstream << c0;
				for (auto j = 1; j < numName; j++)
				{
					auto c1 = sv[j][i];
					if (c0 != c1)
					{
						sstream << "_" << c1;
					}
				}
			}
		}
		else
		{
			sstream << varName;
		}

		return sstream.str();
	}

	GridData GridDataAlgorithm::onCompute(GridDataVec& gridDataVec, const VolumeOptions& options)
	{
		auto comp = gridDataVec.size();
		auto& gridData0 = gridDataVec[0];
		auto numComponentPerGrid = gridData0.gridDataValue->_vecFloat.size();
		auto numComponent = numComponentPerGrid * comp;

		GridData gridData = gridData0.shallowCopy();
		gridData.gridDataValue = std::make_shared<GridDataValue>();

		String mergedVarName = mergeVarName(gridDataVec, options);
		gridData.varName = mergedVarName;

		if (options.preferHalfFloat)
		{
			auto& vecData = gridData.gridDataValue->_vecUint16;
			vecData.resize(numComponent);
			for (auto i = 0; i < numComponentPerGrid; i++)
			{
				for (auto c = 0; c < comp; c++)
				{
					const auto& gridData = gridDataVec[c];
					auto value = gridData.gridDataValue->_vecFloat[i];
					vecData[i * comp + c] = fp16_ieee_from_fp32_value(value);
				}
			}
		}
		else
		{
			auto& vecData = gridData.gridDataValue->_vecFloat;
			vecData.resize(numComponent);
			for (auto i = 0; i < numComponentPerGrid; i++)
			{
				for (auto c = 0; c < comp; c++)
				{
					const auto& gridData = gridDataVec[c];
					auto value = gridData.gridDataValue->_vecFloat[i];
					vecData[i * comp + c] = value;
				}
			}
		}

		return gridData;
	}

	GridData GridDataAlgorithmNone::onCompute(GridDataVec& gridDataVec, const VolumeOptions& options)
	{
		GridData gridData;

		return gridData;
	}

	GridData GridDataAlgorithmFloor::onCompute(GridDataVec& gridDataVec, const VolumeOptions& options)
	{
		auto comp = gridDataVec.size();
		auto& gridData0 = gridDataVec[0];
		auto numComponentPerGrid = gridData0.gridDataValue->_vecFloat.size();
		auto numComponent = numComponentPerGrid * comp;

		GridData gridData = gridData0.shallowCopy();
		gridData.gridDataValue = std::make_shared<GridDataValue>();
		gridData.extent.dimZ = comp;
		gridData.levelData.clear();
		for (const auto& grid : gridDataVec)
		{
			gridData.levelData.push_back(grid.levelData[0]);
		}

		String mergedVarName = mergeVarName(gridDataVec, options);
		gridData.varName = mergedVarName;

		auto dimXY = numComponentPerGrid;
		{
			auto& vecData = gridData.gridDataValue->_vecUint8;
			vecData.resize(numComponent);
			for (auto i = 0; i < numComponentPerGrid; i++)
			{
				for (auto c = 0; c < comp; c++)
				{
					const auto& gridData = gridDataVec[c];
					auto value = gridData.gridDataValue->_vecFloat[i];
					uint8 dbz = VolumeEncoder::encodeInRange(value, { 0.0f,70.0f });
					vecData[i + c * dimXY] = dbz;
				}
			}
		}


		return gridData;
	}
}
